<template>
    <div class="layout-container">
        <div class="layout-container-left" v-loading="loading">
            <div ref="mapRef" class="map" />
        </div>

        <div class="layout-container-right">
            <div class="form-box">
                <el-form label-width="auto">
                    <el-form-item label="带宽参数">
                        <el-input v-model="paramsData.bandwidth" type="number" step="0.5"/>
                    </el-form-item>

                    <el-form-item label="输出网格尺寸">
                        <el-input v-model="paramsData.gridSize" type="number" />
                    </el-form-item>

                    <el-form-item label="是否返回原始密度矩阵">
                        <el-switch v-model="paramsData.includeRawMatrix" />
                    </el-form-item>

                    <el-form-item label="选择权重">
                        <el-radio-group v-model="weightName">
                            <el-radio v-for="item in valueFields" :value="item">{{ item }}</el-radio>
                        </el-radio-group>
                    </el-form-item>

                    <el-form-item>
                        <GeoJsonUpload @uploadSuccess="loadMap" />
                    </el-form-item>

                    <el-form-item>
                        <el-button type="primary" @click="handleCalculate">计算</el-button>
                    </el-form-item>
                </el-form>
            </div>

            <el-divider />

            <div class="info-box">
                <h5>算法说明</h5>
                <p>使用高斯核函数计算空间点的密度分布，通过带宽控制平滑程度（带宽越大，分布越平滑），输出网格密度值用于热力图渲染。</p>

                <h5>使用范围</h5>
                <ul>
                    <li>可视化空间点的聚集程度（如交通事故点、商铺分布的密度）；</li>
                    <li>识别空间热点区域（如人口密集区、服务设施集中区）；</li>
                    <li>适用于点数据（如经纬度坐标），带宽建议通过 Silverman 法则自动计算。</li>
                </ul>
            </div>
        </div>

        <Result v-model="resultShow" :resultData="resultData" />
    </div>
</template>

<script setup>
import { onMounted, onUnmounted, ref } from "vue"
import Map                             from "ol/Map"
import View                            from "ol/View"
import GeoJSON                         from "ol/format/GeoJSON"
import VectorLayer                     from "ol/layer/Vector"
import VectorSource                    from "ol/source/Vector"
import { Circle, Fill, Stroke, Style } from "ol/style"
import { fromLonLat }                  from "ol/proj"
import TileLayer                       from "ol/layer/Tile"
import XYZ                             from "ol/source/XYZ"
import GeoJsonUpload                   from "@/components/GeoJsonUpload.vue"
import { kde }                         from "@/api/spatial.js"
import Result                          from "./components/Result.vue"
import { ElMessage }                   from "element-plus"

let weightName = ref("value")

let paramsData = ref({
    points          : [],
    bandwidth       : 1.5,
    gridSize        : 35,
    includeRawMatrix: true,
})

let resultShow = ref(false)
let resultData = ref({})
let loading    = ref(false)

function handleCalculate(){
    if(!paramsData.value.points){
        ElMessage.error("带宽参数不能为空")
        return
    }

    if(!paramsData.value.gridSize){
        ElMessage.error("输出网格尺寸不能为空")
        return
    }

    if(!weightName.value){
        ElMessage.error("请选择权重")
        return
    }

    paramsData.value.points = geojsonData.features.map(item => {
        return {
            x     : item.properties.POINT_X,
            y     : item.properties.POINT_Y,
            weight: item.properties[weightName.value],
        }
    })

    loading.value = true

    kde(paramsData.value).then(res => {
        resultData.value = res.data
        resultShow.value = true
    }).finally(() => {
        loading.value = false
    })
}

// 地图相关
let mapRef      = ref(null)
let map         = null
let geojsonData = null
let baseLayer   = null
let geoLayer    = null

// 销毁现有地图
function destroyMap(){
    if(map){
        // 移除所有图层
        if(baseLayer){
            map.removeLayer(baseLayer)
            baseLayer = null
        }
        if(geoLayer){
            map.removeLayer(geoLayer)
            geoLayer = null
        }
        // 清除地图实例
        map.setTarget(null)
        map = null
    }
}

let valueFields = ref([])

// 加载地图数据
function loadMap(data){
    destroyMap()
    // 缓存
    geojsonData       = data
    valueFields.value = Object.keys(data?.features?.[0]?.properties || {})
    weightName.value  = valueFields.value?.[0] || ""

    // 基础图层
    baseLayer = new TileLayer({
        source: new XYZ({
            url: "https://webrd0{1-4}.is.autonavi.com/appmaptile?style=7&x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1",
        }),
    })

    // 矢量图层
    geoLayer = new VectorLayer({
        source: new VectorSource({
            features: new GeoJSON().readFeatures(geojsonData, {
                dataProjection   : "EPSG:4326",
                featureProjection: "EPSG:3857",
            }),
        }),
        style : new Style({
            fill  : new Fill({ color: "rgba(75, 192, 192, 0.1)" }),
            stroke: new Stroke({ color: "#c04b8d", width: 2, lineDash: [ 5, 3 ] }),
            image : new Circle({
                radius: 5,
                fill  : new Fill({ color: "#84c1ec" }),
                stroke: new Stroke({ color: "#ffffff", width: 1.5 }),
            }),
        }),
    })

    // 创建map
    map = new Map({
        target  : mapRef.value,
        layers  : [ baseLayer, geoLayer ],
        view    : new View({
            center : fromLonLat([ 104.114129, 35.675387 ]),
            zoom   : 5,
            maxZoom: 18,
        }),
        controls: [],
    })
}

onMounted(() => {
    fetch("/sourceData.geojson")
    .then(response => response.json())
    .then(loadMap)
    .catch(error => console.error("加载GeoJSON失败:", error))
})

onUnmounted(() => {
    if(map){
        map.setTarget(null)
        map = null
    }
})
</script>

<style scoped>
.map {
    height: 100%;
    width: 100%;
    position: relative;
}
</style>
